'''
Created on Dec 21, 2009

@author: duc
'''
from PIL import Image
import math
angle = -45

def getPixel(x,y,im):
    if 0<= x and x < im.size[0] and 0 <= y and y <= im.size[1]:
        pix = im.load()
        return pix[x,y]
    else:
        return None
def rotateByAreaMapping(im, newIm, translate):
    newPix = newIm.load()
    for x in range(newIm.size[0]):
        for y in range(newIm.size[1]):
            try:
                print x,y
                oldX, oldY = rotate( (x + translate, y), -angle)
                
                #The hard way with area weighting
                deltaX = (int(oldX) - oldX)*16
                deltaY = (int(oldY) - oldY)*16
                
                oldPix = im.load()
                
                PixelS00 = oldPix[oldX, oldY]
                PixelS01 = oldPix[oldX, oldY+1]
                PixelS10 = oldPix[oldX+1, oldY]
                PixelS11 = oldPix[oldX+1, oldY+1]
                
                destPixel = [0,0,0]
                
                for i in range (3):                    
                    destPixel[i] = ((16 - deltaX) * (16 - deltaY) * PixelS00[i] +
                                      deltaX * (16 - deltaY) * PixelS10[i]  +
                                      (16 - deltaX) * deltaY * PixelS01[i]  +
                                      deltaX * deltaY * PixelS11[i]  + 128) / 256;
                newPix[x,y] = ( destPixel[0], destPixel[1], destPixel[2])
                #The easy way: with no area weighting
                #a = getPixel(oldX, oldY, im)
                #if (a != None):
                #    newPix[x,y] = a
            except IndexError, message:
                print "ERROR:", message, x,y 
    newIm.save("out.png")
    print "xong"
    
im = Image.open("/Users/duc/Documents/workspace/pilTest/src/test.png")
print im.format , im.size, im.mode

oldPix = im.load()

def rotate(point,angle):
    angle = angle * math.pi/180
    rX = point[0]*math.cos(angle) - point[1]*math.sin(angle) 
    rY = point[0]*math.sin(angle) + point[1]*math.cos(angle)  
    return ( rX, rY  )

box = [(0,0), (im.size[0],0), (im.size[0], im.size[1]), (0, im.size[1])]
#print len(box)
newBox = []
for p in box:
    newBox.append(rotate(p,angle))

maxX = newBox[0][0]
minX = newBox[0][0]
maxY = newBox[0][1]
minY = newBox[0][1]

for p in newBox:
    if p[0] > maxX:
        maxX = p[0]
    if p[0] < minX:
        minX = p[0]
    if p[1] > maxY:
        maxY = p[1]
    if p[1] < minY:
        minY = p[1]

translate = minX
newWidth = maxX - minX + 1
newHeight = maxY - minY + 1

newIm = Image.new(im.mode, (newWidth, newHeight))

rotateByAreaMapping(im, newIm, translate)    
'''
new =im.rotate(45)
new.save("outPro.png")
'''

              
    def TransformRGB(self, matrixA, width, height):
        new = Image.new("RGBA",(width,height))
        newPix = new.load()
    #wx.MessageBox(str(len(self.srcImage.load()[0,0])))
        start = time.time()
        for x in range(width):
            for y in range(height):
                #try:
                # CODE HERE
                oldX, oldY = matrix.Matrix.MatrixToPoint(matrix.Matrix.MultiplyMatrix(matrix.Matrix.InverseMatrix(matrixA), matrix.Matrix.PointToMatrix((x,y))))

                
                if oldX < 0 or oldY < 0 or oldX > self.srcImage.size[0] or oldY > self.srcImage.size[1]:
                    newPix[x,y] = (0,0,0,0)
                    continue
                    
                # CODE HERE

                #The hard way with area weighting
                
                deltaX = (oldX-int(oldX))*16
                deltaY = (oldY-int(oldY))*16
                              
                PixelS00 = convert.Convert.getPixel(oldX,oldY,self.srcImage)
                PixelS01 = convert.Convert.getPixel(oldX,oldY+1,self.srcImage)
                PixelS10 = convert.Convert.getPixel(oldX+1,oldY,self.srcImage)
                PixelS11 = convert.Convert.getPixel(oldX+1,oldY+1,self.srcImage)
                
                destPixel = [0,0,0,0]
                
                destPixel[0] = ((16 - deltaX) * (16 - deltaY) * PixelS00[0] +
                                      deltaX * (16 - deltaY) * PixelS10[0]  +
                                      (16 - deltaX) * deltaY * PixelS01[0]  +
                                      deltaX * deltaY * PixelS11[0]) / 256
                destPixel[1] = ((16 - deltaX) * (16 - deltaY) * PixelS00[1] +
                                      deltaX * (16 - deltaY) * PixelS10[1]  +
                                      (16 - deltaX) * deltaY * PixelS01[1]  +
                                      deltaX * deltaY * PixelS11[1]) / 256
                destPixel[2] = ((16 - deltaX) * (16 - deltaY) * PixelS00[2] +
                                      deltaX * (16 - deltaY) * PixelS10[2]  +
                                      (16 - deltaX) * deltaY * PixelS01[2]  +
                                      deltaX * deltaY * PixelS11[2]) / 256
                destPixel[3] = 255                                                                                                                
                newPix[x,y] = ( destPixel[0], destPixel[1], destPixel[2],destPixel[3])
        
        wx.MessageBox(str(time.time() - start))
        return new
    def TransformRGBA(self, matrixA, width, height):
        new = Image.new("RGBA",(width,height))
        newPix = new.load()
        #wx.MessageBox(str(len(self.srcImg[0,0])))
        start = time.time()
        for x in range(width):
            for y in range(height):
                #try:
                # CODE HERE
                oldX, oldY = matrix.Matrix.MatrixToPoint(matrix.Matrix.MultiplyMatrix(matrix.Matrix.InverseMatrix(matrixA), matrix.Matrix.PointToMatrix((x,y))))

                
                if oldX < 0 or oldY < 0 or oldX > self.srcImage.size[0] or oldY > self.srcImage.size[1]:
                    newPix[x,y] = (0,0,0,0)
                    continue
                    
                # CODE HERE

                #The hard way with area weighting
                
                deltaX = (oldX-int(oldX))*16
                deltaY = (oldY-int(oldY))*16
                              
                PixelS00 = convert.Convert.getPixel(oldX,oldY,self.srcImage)
                PixelS01 = convert.Convert.getPixel(oldX,oldY+1,self.srcImage)
                PixelS10 = convert.Convert.getPixel(oldX+1,oldY,self.srcImage)
                PixelS11 = convert.Convert.getPixel(oldX+1,oldY+1,self.srcImage)
                
                destPixel = [0,0,0,0]
                
                destPixel[0] = ((16 - deltaX) * (16 - deltaY) * PixelS00[0] +
                                      deltaX * (16 - deltaY) * PixelS10[0]  +
                                      (16 - deltaX) * deltaY * PixelS01[0]  +
                                      deltaX * deltaY * PixelS11[0]) / 256
                destPixel[1] = ((16 - deltaX) * (16 - deltaY) * PixelS00[1] +
                                      deltaX * (16 - deltaY) * PixelS10[1]  +
                                      (16 - deltaX) * deltaY * PixelS01[1]  +
                                      deltaX * deltaY * PixelS11[1]) / 256
                destPixel[2] = ((16 - deltaX) * (16 - deltaY) * PixelS00[2] +
                                      deltaX * (16 - deltaY) * PixelS10[2]  +
                                      (16 - deltaX) * deltaY * PixelS01[2]  +
                                      deltaX * deltaY * PixelS11[2]) / 256
                destPixel[3] = ((16 - deltaX) * (16 - deltaY) * PixelS00[3] +
                      deltaX * (16 - deltaY) * PixelS10[3]  +
                      (16 - deltaX) * deltaY * PixelS01[3]  +
                      deltaX * deltaY * PixelS11[3]) / 256
                                                                                                       
                newPix[x,y] = ( destPixel[0], destPixel[1], destPixel[2],destPixel[3])
        wx.MessageBox(str(time.time() - start))
        return new
    
    def Transform(self,matrixA,width,height):


        if self.srcImage.mode == "RGBA":
            self.new = self.TransformRGBA(matrixA, width, height)
        else:
            self.new = self.TransformRGB(matrixA, width, height)
        self.srcImage = self.new
        src = convert.Convert.pilToBitmap(self.new)
        self.prePix.Destroy()
        self.prePix = wx.StaticBitmap(self.scrollW,01,src)
        
        self.scrollW.SetScrollbars(20,20,src.GetWidth()/20,src.GetHeight()/20)
        self.refreshSize()  
